package com.wangyh.edit.prettyedit.tree;

import com.wangyh.edit.prettyedit.constant.EditConstant;
import com.wangyh.edit.prettyedit.mainframe.MainFrameView;
import com.wangyh.edit.prettyedit.util.FileImgUtils;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;

import java.io.File;
import java.util.*;

/**
 * 左侧树构建类
 * @author wangyh
 */
public class FileTreeCellImpl extends TreeCell<File> {

    //树控件
    private TreeView treeView;

    private TextField textField;
    private final ContextMenu folderMenu = new ContextMenu();

    private final ContextMenu fileMenu = new ContextMenu();

    public FileTreeCellImpl(TreeView tree,MainFrameView mainFrameView) {
        //文件夹
        MenuContextFolder.generateFileMenu(tree,folderMenu,mainFrameView);
        //文件
        MenuContextFile.generateFileMenu(tree,fileMenu);

        treeView = tree;

        //拖动事件
        setOnDragDetected((MouseEvent event) -> {
            // drag was detected, start a drag-and-drop gesture
            // allow Move transfer mode only
            Dragboard db = startDragAndDrop(TransferMode.MOVE);

            // Put the Part on the dragboard
            // From: https://stackoverflow.com/a/30916660/780350
            ClipboardContent content = new ClipboardContent();
            DataFormat objectDataFormat = new DataFormat("application/x-java-serialized-object");
            content.put(objectDataFormat, getItem());
            db.setContent(content);

            event.consume();
        });

//        setOnDragDropped((DragEvent event) -> {
//            try {
//                Dragboard db = event.getDragboard();
//                boolean success = false;
//                if (db.hasContent(objectDataFormat)) {
//                    File droppedPart = (File)db.getContent(objectDataFormat);
//                    File targetStoryItem = getItem();
//
//                    // Question: How to handle drops between leaf items or
//                    // before the initial leaf or after the final leaf.
//                    if (targetStoryItem instanceof File) {
//                        File story = (File) targetStoryItem;
//
//                        updateStoryWith(droppedPart, story);
//                        addPartTo(cell.getTreeItem(), droppedPart);
//                        success = true;
//                    }
//                }
//
//                event.setDropCompleted(success);
//                event.consume();
//            } catch (Exception e) {
//                System.out.println(e.getMessage());
//            }
//        });

//        setOnDragDone((DragEvent event) -> {
//            /*
//             * the drag and drop gesture ended
//             * if the data was successfully moved, clear it
//             */
//            if (event.getTransferMode() == TransferMode.MOVE) {
//                // TODO: remove the part that got moved.
//                File item = getItem();
//                TreeItem<File> ti = getTreeItem();
//                TreeItem<File> pti = ti.getParent();
//                pti.getChildren().remove(ti);
//
//                File psi = pti.getValue();
//                boolean removed = removePartFrom(psi, item);
//            }
//            event.consume();
//        });
    }

    @Override
    public void startEdit() {
        super.startEdit();

        if (textField == null) {
            createTextField();
        }
        setText(null);
        setGraphic(textField);
        textField.selectAll();
        textField.setText((String) getItem().getName());
        textField.requestFocus();
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();

        setText((String) getItem().getName());
        setGraphic(getTreeItem().getGraphic());
    }

    @Override
    public void updateItem(File item, boolean empty) {
        super.updateItem(item, empty);

//        System.out.println(item + ":" + empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(getTreeItem().getGraphic());
//                if (!getTreeItem().isLeaf()&&getTreeItem().getParent()!= null){
//                    setContextMenu(folderMenu);
//                }
                if(getItem().isDirectory()){
                    setContextMenu(folderMenu);
                }else{
                    setContextMenu(fileMenu);
                }
            }
        }
    }

    private void createTextField() {
        textField = new TextField(getString());
//        int dex=treeView.getSelectionModel().getSelectedIndex();
        textField.setOnKeyReleased((KeyEvent t) -> {
            if (t.getCode() == KeyCode.ENTER) {
                //根节点，不允许修改
                TreeItem<File> parent = getTreeItem().getParent();
                if(parent ==null){
                    Alert alert = new Alert(Alert.AlertType.WARNING);
                    alert.setContentText("根节点不允许修改");
                    alert.setTitle("修改失败！");
                    alert.setHeaderText("警告！");
                    alert.show();
                    return;
                }

                //回车键，修改文件名
                String path = parent.getValue().getAbsolutePath();
                File newFile = new File(path + File.separator + textField.getText());
                //如果是一致，说明是新建
                if((path + File.separator + textField.getText()).equals(getItem().getAbsolutePath())){
                    //新旧一样，说明新建，不用校验。 或者只是点击了一下编辑模式，然后没有改名。
                    updateFileName(newFile,parent);
                }else{
                    //纯改名模式
                    if(newFile.exists()){
                        Alert alert = new Alert(Alert.AlertType.WARNING);
                        alert.setContentText("命名文件已存在，请修改文件名");
                        alert.setTitle("修改失败！");
                        alert.setHeaderText("警告！");
                        alert.show();
                        return;
                    }
                    File oldFile = new File(getItem().getAbsolutePath());
                    boolean flag = oldFile.renameTo(newFile);
                    if(!flag){
                        System.out.println("修改：" + flag);
                        Alert alert = new Alert(Alert.AlertType.WARNING);
                        alert.setContentText("修改文件名失败！");
                        alert.setTitle("系统异常，修改失败！");
                        alert.setHeaderText("警告！");
                        alert.show();
                        return;
                    }

                    //文件和文件夹处理方式不一样
                    if(newFile.isDirectory()){
                        updateFolderName(parent,newFile);
                    }else{
                        updateFileName(newFile, parent);
                    }
                }
            } else if (t.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
            }
        });
    }

    private String getString() {
        return getItem() == null ? "" : getItem().getName().toString();
    }

    /**
     * 更新文件夹的名称
     * @param newFile
     * @param parent
     */
    private void updateFileName(File newFile, TreeItem<File> parent){
        //子结点更新
        getTreeItem().setValue(newFile);

        //结点上同步显示，因为父结点已修改，因此这里不要再设置了
        setText(textField.getText());
        setGraphic(getTreeItem().getGraphic());

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if(getTreeItem()==null){
                    System.out.println("null");
                }
                ObservableList<TreeItem<File>> children = parent.getChildren();
                children.sort(Comparator.comparing(TreeItem::getValue));
                System.out.println("列表排序：" + children.toString());
//                        Collections.sort(children, String.CASE_INSENSITIVE_ORDER);

                //排完序后，在让他选中修改的结点
                for(int i=0; i<children.size(); i++){
                    TreeItem<File> fileTreeItem = children.get(i);
                    if(fileTreeItem.getValue().getAbsolutePath().equals(newFile.getAbsolutePath())){
                        treeView.getSelectionModel().select(fileTreeItem);
                        break;
                    }
                }
            }
        });
    }

    private void updateFolderName(TreeItem<File> parent, File newFile){
        //父节点更新数据
        parent.getChildren().clear();

        //更新父亲
        for(final File file: parent.getValue().listFiles()){
            if(file.isDirectory()){
                ImageView folderIcon = new ImageView(
                        new Image(MainFrameView.class.getResourceAsStream("/img/folder.png"))
                );
                folderIcon.setFitHeight(EditConstant.treeIconHeight);
                folderIcon.setFitWidth(EditConstant.treeIconWeight);
                parent.getChildren().add(new FileTreeItem(file,folderIcon));
            }else{
                //设置图标
                ImageView fileIcon = FileImgUtils.getFileImageView(file);
                parent.getChildren().add(new FileTreeItem(file,fileIcon));
            }
        }

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                parent.setExpanded(true);
                ObservableList<TreeItem<File>> children = parent.getChildren();
                children.sort(Comparator.comparing(TreeItem::getValue));
                System.out.println("列表排序：" + children.toString());
//                        Collections.sort(children, String.CASE_INSENSITIVE_ORDER);

                //排完序后，在让他选中修改的结点
                for(int i=0; i<children.size(); i++){
                    TreeItem<File> fileTreeItem = children.get(i);
                    if(fileTreeItem.getValue().getAbsolutePath().equals(newFile.getAbsolutePath())){
                        treeView.getSelectionModel().select(fileTreeItem);
                        break;
                    }
                }
            }
        });

        //定位到位置
//                System.out.println(dex);
//                treeView.getSelectionModel().select(dex);
    }

//    boolean removePartFrom(IStoryItem si, IStoryItem pi) {
//        if (!(si instanceof Story)) return false;
//        if (!(pi instanceof Part)) return false;
//        Story story = (Story) si;
//        Part part = (Part) pi;
//        List<Part> plist = new LinkedList<>(Arrays.asList(story.parts));
//        if (!plist.contains(part)) return false;
//        boolean removed = plist.remove(part);
//        story.parts = plist.toArray(new Part[plist.size()]);
//        return removed;
//    }
//
//    void addPartTo(TreeItem<IStoryItem> storyItem, Part part) {
//        TreeItem<IStoryItem> partItem = new TreeItem<>(part);
//        storyItem.getChildren().add(partItem);
//    }

//    private void updateStoryWith(File droppedPart, File story) {
//        List<File> partsList = new ArrayList<>(Arrays.asList(story.parts));
//        partsList.add(droppedPart);
//        Part [] newParts = (Part[])partsList.toArray(new Part[partsList.size()]);
//
//        int idx = 1;
//        for (Part part : newParts) {
//            part.partnumber = idx++;
//        }
//
//        story.parts = newParts;
//    }


}
